package com.sxj.corejava.code01_线程;

/**
 * @author 石小俊
 * @date 2023年11月2023/11/16日 19:04
 */
public class Test09_生产者消费者问题 {

    public static void main(String[] args) {
        ProductPool pool = new ProductPool();
        // 生产者线程
        Producer p1 = new Producer(pool,"生产者p1");
        Producer p2= new Producer(pool,"生产者p2");
        Producer p3= new Producer(pool,"生产者p3");

        // 消费者线程
        Consumer c1 = new Consumer(pool,"消费者c1");
        Consumer c2 = new Consumer(pool,"消费者c2");

        p1.start();
        p2.start();
        p3.start();
        c1.start();
        c2.start();
    }

}

class ProductPool {
    // 当前仓库中商品数量
    private int num;
    // 仓库中商品的数量上限
    private static final int MAX_COUNT = 20;

    /**
     * 生产商品
     * 生产者负责生产商品
     * 每次生产,仓库中商品数量+1
     *
     * @return 当前库存
     */
    public int put() {
        num++;
        return num;
    }

    /**
     * 消费商品
     * 消费者负责消费商品
     * 每次消费,仓库中商品数量-1
     *
     * @return 当前库存
     */
    public int get() {
        num--;
        return num;
    }

    /**
     * 判断当前仓库中库存是否达到了上限
     *
     * @return
     */
    public boolean isFull() {
        return this.num == MAX_COUNT;
    }

    /**
     * 判断当前仓库中库存是否为空
     *
     * @return
     */
    public boolean isEmpty() {
        return this.num == 0;
    }
}

class Producer extends Thread {
    private ProductPool pool;
    private String name;

    public Producer(ProductPool pool, String name) {
        this.pool = pool;
        this.name = name;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (pool) {
                // 根据仓库中的库存是否达到了上限判断是否需要生产
                if (pool.isFull()) {
                    // 如果仓库中的库存达到了上限,则停止生产
                    try {
                        pool.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    // 如果仓库中的库存没有达到上限,则生产商品
                    int num = pool.put();
                    System.out.println(this.name + "生产了一件商品,当前库存数量为:" + num);
                    // 生产了商品之后库存一定不可能为空,需要消费者继续进行消费
                    // 此时需要唤醒消费者线程
                    pool.notifyAll();
                }
            }
            try {
                Thread.sleep(600);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer extends Thread {
    private ProductPool pool;
    private String name;

    public Consumer(ProductPool pool, String name) {
        this.pool = pool;
        this.name = name;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (pool) {
                // 根据仓库的库存数量判断是否可以消费
                if (pool.isEmpty()) {
                    // 如果当前库存为空,则无法消费,需要等待生产者进行生产
                    try {
                        pool.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    // 如果库存不为空,则可以消费
                    int num = pool.get();
                    System.out.println(this.name + "消费了一件商品,当前库存数量为:" + num);
                    // 消费了商品之后,需要唤醒生产者继续生产商品
                    pool.notifyAll();
                }
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
